package com.springboot.oauth2.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Collectors;

// 资源服务配置
@Configuration
// 开启资源服务配置
@EnableResourceServer
// 开启方法授权
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
  @Autowired MyAuthenticationHandler authenticationHandler;
  // 1.资源服务安全配置

  // JWT令牌
  @Bean
  public TokenStore tokenStore() {
    return new JwtTokenStore(jwtAccessTokenConverter());
  }

  // 设置JWT签名密钥。它可以是简单的MAC密钥，也可以是RSA密钥

  // JWT令牌校验工具
  @Bean
  public JwtAccessTokenConverter jwtAccessTokenConverter() {
    JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
    jwtAccessTokenConverter.setVerifierKey(getPubKey());
    return jwtAccessTokenConverter;
  }
  public String getPubKey() {
    Resource resource = new ClassPathResource("pubKey.txt");
    try {
      InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream());
      BufferedReader br = new BufferedReader(inputStreamReader);
      return br.lines().collect(Collectors.joining("\n"));
    } catch (IOException ioe) {
      return null;
    }
  }

  @Override
  public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
    // 资源ID
    resources.resourceId("res1").tokenStore(tokenStore());
  }

  // 2.资源服务的资源的授权配置，比如那些资源放行，那些资源需要什么权限等等
  @Override
  public void configure(HttpSecurity http) throws Exception {
    ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry =
        http.authorizeRequests();
    // 动态配置权限
    // 1查询权限配置信息集合，比如路径对应权限（/dept/add---dept:add）
    // registry.antMatchers("/dept/delete").hasAnyRole("ROLE_admin");
    // 2遍历权限信息集合，然后使用下面的语句配置资源需要什么权限
    /*registry.antMatchers("/dept/add").hasAuthority("dept:add");*/

    http.exceptionHandling()
        .authenticationEntryPoint(authenticationHandler)
        .accessDeniedHandler(authenticationHandler);
    registry
        //.antMatchers("/show/*")
        //.permitAll()

        .antMatchers("/**")
        .access("#oauth2.hasScope('all')")// 校验scope必须为all ， 对应认证服务的客户端详情配置的clientId
        // 关闭跨域伪造检查
        .and()
        .csrf()
        .disable()
        // 把session设置为无状态，意思是使用了token，那么session不再做数据的记录
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
  }
}
